package sys_config

import (
	"fmt"
	"github.com/ilyakaznacheev/cleanenv"
	"github.com/sirupsen/logrus"
	"io/fs"
	"os"
	"strings"
	"sync/atomic"
	"time"
	"unsafe"
)

var (
	ptr unsafe.Pointer
)

// 系统配置信息
type SysConfigInfo struct {
	HomeDir         string
	YmlConfPath     string
	EnvConfPath     string
	WebEndpoint     WebEndpointEnv     `yaml:"web-endpoint"`
	ConfigTable     ConfigTableEnv     `yaml:"config-table"`
	Storage         StorageEnv         `yaml:"storage"`
	Logging         LoggingEnv         `yaml:"logger"`
	System          SystemEnv          `yaml:"system"`
	SerialAddrAlias SerialAddrAliasEnv `yaml:"serial-addr-alias"`
}

type LoggingEnv struct {
	Formatter         string `yaml:"formatter" env:"GW_LOGGING_FORMATTER" env-default:"text"`
	Output            string `yaml:"output" env:"GW_LOGGING_OUTPUT" env-default:"stdout"`
	Path              string `yaml:"path" env:"GW_LOGGING_PATH" env-default:""`
	MaxHistory        int    `yaml:"max-history" env:"GW_LOGGING_MAX_HISTORY" env-default:"30"`
	Level             string `yaml:"level" env:"GW_LOGGING_LEVEL" env-default:"warn"`
	PrintReportCaller bool   `yaml:"print-report-caller" env:"GW_LOGGING_PRINT_REPORT_CALLER" env-default:"true"`
	MaxFileSizeMb     int    `yaml:"max-file-size-mb" env:"GW_LOGGING_MAX_FILE_SIZE_MB" env-default:"100"`
	MaxFileCount      uint   `yaml:"max-file-count" env:"GW_LOGGING_MAX_FILE_COUNT" env-default:"0"`
}

// 配置表环境
type ConfigTableEnv struct {
	Type       string `yaml:"type" env:"GW_CONFIG_TABLE_TYPE" env-default:"sql" `
	Path       string `yaml:"path" env:"GW_CONFIG_TABLE_PATH" env-default:"" `
	Datasource struct {
		DriverClassName string `yaml:"driver-class-name" env:"GW_CONFIG_TABLE_DATASOURCE_DRIVER_CLASS_NAME" env-default:"org.sqlite.JDBC"`
		Url             string `yaml:"url" env:"GW_CONFIG_TABLE_DATASOURCE_URL" `
		Username        string `yaml:"username" env:"GW_CONFIG_TABLE_DATASOURCE_USERNAME" env-default:"gewu"`
		Password        string `yaml:"password" env:"GW_CONFIG_TABLE_DATASOURCE_PASSWORD" env-default:"gewu"`
	}
}

// 存储配置
type StorageEnv struct {
	Path           string            `yaml:"path" env:"GW_STORAGE_PATH" env-default:""`
	LatestStorage  LatestStorageEnv  `yaml:"latest" `
	HistoryStorage HistoryStorageEnv `yaml:"history" `
}

// 最新值存储
type LatestStorageEnv struct {
	Type string `yaml:"type" env:"GW_STORAGE_LATEST_TYPE" env-default:"sql"`
	//写数据时，队列缓冲大小. 队列溢出时数据将丢弃
	FlushCacheSize  int `yaml:"flush-cache-size" env:"GW_STORAGE_LATEST_FLUSH_CACHE_SIZE" env-default:"360"`
	FlushIntervalMs int `yaml:"flush-interval-ms" env:"GW_STORAGE_LATEST_FLUSH_INTERVAL_MS" env-default:"350"`
	FlushSize       int `yaml:"flush-size" env:"GW_STORAGE_LATEST_FLUSH_SIZE" env-default:"120"`
	Datasource      struct {
		DriverClassName string `yaml:"driver-class-name" env:"GW_STORAGE_LATEST_DATASOURCE_DRIVER_CLASS_NAME" env-default:"org.sqlite.JDBC"`
		Url             string `yaml:"url" env:"GW_STORAGE_LATEST_DATASOURCE_URL" `
		Username        string `yaml:"username" env:"GW_STORAGE_LATEST_DATASOURCE_USERNAME" env-default:"gewu"`
		Password        string `yaml:"password" env:"GW_STORAGE_LATEST_DATASOURCE_PASSWORD" env-default:"gewu"`
	}
}

// 历史库配置
type HistoryStorageEnv struct {
	Enable     bool   `yaml:"enable" env:"GW_STORAGE_HISTORY_ENABLE" env-default:"false"`
	Type       string `yaml:"type" env:"GW_STORAGE_HISTORY_TYPE" env-default:"sqlite"`
	Datasource struct {
		DriverClassName string `yaml:"driver-class-name" env:"GW_STORAGE_HISTORY_DATASOURCE_DRIVER_CLASS_NAME" env-default:"org.sqlite.JDBC"`
		Url             string `yaml:"url" env:"GW_STORAGE_HISTORY_DATASOURCE_URL" `
		Username        string `yaml:"username" env:"GW_STORAGE_HISTORY_DATASOURCE_USERNAME" env-default:"gewu"`
		Password        string `yaml:"password" env:"GW_STORAGE_HISTORY_DATASOURCE_PASSWORD" env-default:"gewu"`
	}
}

// web 端点配置
type WebEndpointEnv struct {
	Enable      bool   `yaml:"enable" env:"GW_WEB_ENDPOINT_ENABLE" env-default:"true" `
	Address     string `yaml:"address" env:"GW_WEB_ENDPOINT_ADDRESS" env-default:"0.0.0.0" `
	Port        string `yaml:"port" env:"GW_WEB_ENDPOINT_PORT" env-default:"8080" `
	ContextPath string `yaml:"context-path" env:"GW_WEB_ENDPOINT_CONTEXT_PATH" env-default:"/"`
	RunMode     string `yaml:"run-mode" env:"GW_WEB_ENDPOINT_RUN_MODE" env-default:"release"`
	Security    struct {
		Username string `yaml:"username" env:"GW_WEB_ENDPOINT_SECURITY_USER" env-default:"admin"`
		Password string `yaml:"password" env:"GW_WEB_ENDPOINT_SECURITY_PASSWORD" env-default:"admin"`
	}
}

// 系统环境配置
type SystemEnv struct {
	EnvUpdateInterval int   `yaml:"env-update-interval" env:"GW_SYSTEM_ENV_UPDATE_INTERVAL" env-default:"7" `
	GoMaxProcs        int   `yaml:"go-max-procs" env:"GW_SYSTEM_GO_MAX_PROCS" env-default:"-1" `
	Stack             int64 `yaml:"stack" env:"GW_SYSTEM_STACK" env-default:"1" `
}

// ConfigInfo 全局读取
func ConfigInfo() SysConfigInfo {
	return *(*SysConfigInfo)(atomic.LoadPointer(&ptr))
}

// HomeDir 家目录
func HomeDir() string {
	return (*SysConfigInfo)(atomic.LoadPointer(&ptr)).HomeDir
}

func isPathError(err error) bool {
	switch err.(type) {
	case *fs.PathError:
		return true
	}
	return false
}

// LoadConfig 配置文件
func LoadConfig(homeDir string) (SysConfigInfo, error) {

	//获取家目录
	if strings.TrimSpace(homeDir) == "" {
		val := os.Getenv("GATEWAY_HOME_DIR")
		if strings.TrimSpace(val) != "" {
			homeDir = val
		} else {
			homeDir = "."
			currentWorkingDir, err := os.Getwd()
			if err == nil {
				homeDir = currentWorkingDir
			} else {
				logrus.Error("获取当前目录失败 error", err)
			}
		}
	}

	fmt.Printf("\n ===== 系统配置 ===== \n")
	fmt.Printf("系统家目录 %s \n", homeDir)

	cfg := &SysConfigInfo{
		HomeDir: homeDir,
	}

	separator := string(os.PathSeparator)

	//读取yml配置
	//${homeDir}/config/gateway.yml
	//${homeDir}/gateway.yml
	//./config/gateway.yml
	//./gateway.yml
	ymlPaths := []string{
		homeDir + separator + "config" + separator + "gateway.yml",
		homeDir + separator + "gateway.yml",
		"." + separator + "config" + separator + "gateway.yml",
		"." + separator + "gateway.yaml",
	}

	ymlPath := ""
	for _, path := range ymlPaths {
		err := cleanenv.ReadConfig(path, cfg)
		if err == nil {
			ymlPath = path
			break
		}

		if isPathError(err) {
			continue
		}

		logrus.Warn("系统yml配置读取失败 error ", err)
		break
	}

	//读取gateway.env配置
	//${homeDir}/config/gateway.env
	//${homeDir}/gateway.env
	//./config/gateway.env
	//./gateway.env
	envPaths := []string{
		homeDir + separator + "config" + separator + "gateway.env",
		homeDir + separator + "gateway.env",
		"." + separator + "config" + separator + "gateway.env",
		"." + separator + "gateway.env",
	}

	envPath := ""
	for _, path := range envPaths {
		err := cleanenv.ReadConfig(path, cfg)
		if err == nil {
			envPath = path
			break
		}

		if isPathError(err) {
			continue
		}

		logrus.Warn("系统env配置读取失败 error ", err)
		break
	}

	cfg.EnvConfPath = envPath
	cfg.YmlConfPath = ymlPath
	if envPath != "" || ymlPath != "" {
		if ymlPath != "" {
			fmt.Printf("已加载yml配置文件 %s \n", ymlPath)
		}
		if envPath != "" {
			fmt.Printf("已加载env配置文件 %s \n", envPath)
		}
	} else {
		logrus.Warn("未读取到yml或env配置文件")
	}

	//从系统环境变量中读取
	err := cleanenv.ReadEnv(cfg)
	if err != nil {
		logrus.Warn("系统环境变量加载失败 error ", err)
	}

	atomic.StorePointer(&ptr, unsafe.Pointer(cfg))

	configInfo := ConfigInfo()

	//自动刷新运行环境
	if configInfo.System.EnvUpdateInterval > 0 {
		go func(_cfg *SysConfigInfo, interval time.Duration) {
			//todo 只能执行一次
			for {
				time.Sleep(interval)
				if err := cleanenv.UpdateEnv(_cfg); err != nil {
					logrus.Warn("系统环境更新失败 error ", err)
				}
			}
		}(cfg, time.Duration(configInfo.System.EnvUpdateInterval)*time.Second)
	}

	return configInfo, nil
}
